﻿using DrawTools.Serialize;
using DrawTools.Utils;
using System;
using System.Windows;
using System.Windows.Media;

namespace DrawTools.Tools
{
    /// <summary>
    /// 长度
    /// </summary>
    [SerializerType(typeof(DrawLengthSerializer))]
    public sealed class LengthDrawTool : DrawGeometryBase
    {
        #region 字段

        private Point? startPoint, endPoint;
        private Point center, textPoint;
        private FormattedText formattedText;
        private double angle;
        private Dpi dpi;
        private double _length;

        private EllipseGeometry startEllipseGeo, endEllipseEndGeo;

        protected override Point BeginingPoint
        {
            get
            {
                if (this.startPoint == null || this.endPoint == null) return new Point();
                var point = startPoint.Value;
                if (endPoint.Value.X < startPoint.Value.X)
                {
                    point = endPoint.Value;
                }
                return point;
            }
        }

        /// <summary>
        /// 获取长度的值
        /// </summary>
        /// <returns></returns>
        public double GetValue() => _length;

        #endregion 字段

        public LengthDrawTool(DrawingCanvas drawingCanvas) : base(drawingCanvas)
        {
            DrawingToolType = DrawToolType.Length;

            // 准备要处理的事件
            CanTouchDown = true;
        }

        #region 方法
        public override bool Select(Point point)
        {
            return startEllipseGeo?.FillContains(point) == true || geometry.FillContains(point) || endEllipseEndGeo?.FillContains(point) == true;
        }

        public override bool Select(Geometry select)
        {
            return !Geometry.Combine(geometry, select, GeometryCombineMode.Intersect, null).IsEmpty()
                || !Geometry.Combine(startEllipseGeo, select, GeometryCombineMode.Intersect, null).IsEmpty()
                || !Geometry.Combine(endEllipseEndGeo, select, GeometryCombineMode.Intersect, null).IsEmpty();
        }

        protected override void OnDrawing(DrawingContext dc)
        {
            base.OnDrawing(dc);
            //画文字
            if (!DrawerConfig.Instance.TextShowTogether && !string.IsNullOrEmpty(Text))
            {
                if (formattedText == null)
                {
                    formattedText = GetFormattedText(Text);
                }
                var textGeometry = formattedText.BuildGeometry(textPoint);
                var translate = GetTranslateTransform();
                if (translate != null)
                {
                    var transformGroup = new TransformGroup();
                    transformGroup.Children.Add(new RotateTransform(angle, center.X, center.Y));
                    transformGroup.Children.Add(translate);
                    textGeometry.Transform = transformGroup;
                }
                else
                {
                    textGeometry.Transform = new RotateTransform(angle, center.X, center.Y);
                }
                dc.DrawGeometry(Pen.Brush, null, textGeometry);
            }
            //画端点
            var radius = Pen.Thickness * 1;
            if (startEllipseGeo == null && startPoint.HasValue)
            {
                startEllipseGeo = new EllipseGeometry() { Center = startPoint.Value, RadiusX = radius, RadiusY = radius };
            }
            if (endEllipseEndGeo == null && endPoint.HasValue)
            {
                endEllipseEndGeo = new EllipseGeometry() { Center = endPoint.Value, RadiusX = radius, RadiusY = radius };
            }
            if (startEllipseGeo != null && endEllipseEndGeo != null)
            {
                var arcPen = new Pen(drawingCanvas.Brush, Pen.Thickness * 1.5);
                endEllipseEndGeo.Transform = startEllipseGeo.Transform = GetTranslateTransform();
                dc.DrawGeometry(null, arcPen, startEllipseGeo);
                dc.DrawGeometry(null, arcPen, endEllipseEndGeo);
            }
        }
        #endregion

        #region 鼠标键盘事件

        public override bool OnTouchLeave(Point point, bool isLeaved = false)
        {
            if (!endPoint.HasValue || (startPoint.Value - endPoint.Value).Length < Pen.Thickness)
            {
                drawingCanvas.DeleteVisual(this);
            }
            else
            {
                Draw();
            }
            drawingCanvas.DeleteWorkingDrawTool(this);
            IsFinish = true;
            CanKeyDown = false;
            CanTouchMove = false;
            CanTouchLeave = false;
            if (TouchId == 0 && drawingCanvas.IsMouseCaptured) drawingCanvas.ReleaseMouseCapture();
            return true;
        }

        public override bool OnTouchDown(int touchId, Point point)
        {
            TouchId = touchId;

            if (!startPoint.HasValue)
            {
                drawingCanvas.AddWorkingDrawTool(this);

                dpi = DpiHelper.GetDpiFromVisual(drawingCanvas);
                startPoint = point;
                geometry = new PathGeometry();
                var figure = new PathFigure() { StartPoint = point };
                pathGeometry.Figures.Add(figure);
                CanTouchMove = true;
                if (TouchId != 0 || !drawingCanvas.CaptureMouse()) CanTouchLeave = true;
                drawingCanvas.AddVisual(this);
                return true;
            }
            else
            {
                return OnTouchLeave(point);
            }
        }

        public override bool OnTouchMove(Point point)
        {
            if (startPoint == null)
            {
                startPoint = point;
                return true;
            }
            var start = startPoint.Value;
            if ((start - point).Length < drawingCanvas.StrokeThickness) return true;

            var dc = RenderOpen();
            endPoint = point;

            var distance = CalculateDistance(startPoint.Value.X, startPoint.Value.Y, endPoint.Value.X, endPoint.Value.Y);
            double actualDistance = distance * GlobalPixelSpacingUtils.PixelSpacingValue;
            base.Text = actualDistance.ToString("0.00") + "mm";

            //System.Console.WriteLine($"坐标起点：({startPoint.Value.X},{startPoint.Value.Y})，坐标终点：({endPoint.Value.X},{endPoint.Value.Y})，坐标距离：{distance},PixelSpacing:{GlobalPixelSpacingUtils.PixelSpacingValue}");

            if (!DrawerConfig.Instance.TextShowTogether)
            {
                double? k = null;       // 斜率

                if (start.X == point.X) angle = start.Y > point.Y ? 90 : -90;
                else
                {
                    k = (point.Y - start.Y) / (point.X - start.X);
                    angle = Math.Atan(k.Value) / Math.PI * 180;
                }
                formattedText = GetFormattedText();
                center = new Point((start.X + point.X) / 2, (start.Y + point.Y) / 2);
                var width = Text.Length * FontSize / 2;     // 文字宽度
                textPoint = new Point(center.X - width / 2, center.Y - FontSize * 1.2 - Pen.Thickness);     // 文字左上角，1.2倍行高
                dc.PushTransform(new RotateTransform(angle, center.X, center.Y));
                dc.DrawText(formattedText, textPoint);
                dc.Pop();
            }

            //画端点
            if (startPoint != null)
            {
                var radius = Pen.Thickness * 1;
                var arcPen = new Pen(drawingCanvas.Brush, Pen.Thickness * 1.5);
                //起始端点
                if (startEllipseGeo == null)
                {
                    startEllipseGeo = new EllipseGeometry() { Center = start, RadiusX = radius, RadiusY = radius };
                }
                dc.DrawGeometry(arcPen.Brush, arcPen, startEllipseGeo);
                //终止端点
                endEllipseEndGeo = new EllipseGeometry() { Center = point, RadiusX = radius, RadiusY = radius };
                dc.DrawGeometry(arcPen.Brush, arcPen, endEllipseEndGeo);
            }

            //画线条
            var figure = pathGeometry.Figures[0];
            figure.Segments.Clear();
            figure.StartPoint = start;
            var line = new LineSegment(start, IsStroked) { IsSmoothJoin = true };
            figure.Segments.Add(line);
            line = new LineSegment(point, IsStroked) { IsSmoothJoin = true };
            figure.Segments.Add(line);

            dc.DrawGeometry(null, Pen, geometry);
            dc.Close();
            return true;
        }

        /// <summary>
        /// 计算两个坐标点的距离
        /// </summary>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="x2"></param>
        /// <param name="y2"></param>
        /// <returns></returns>
        private static double CalculateDistance(double x1, double y1, double x2, double y2)
        {
            double distance = Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
            return distance;
        }

        #endregion 鼠标键盘事件

    }
}